#include "StdAfx.h"
#include "DBSqlite.h"
#include "Sqlite/Include/sqlite3.h"

namespace DDM
{
//---------------------------------------------------------------------------------------
DBSqlite::DBSqlite(void)
{
}
DBSqlite::~DBSqlite(void)
{
    this->close();
}
//---------------------------------------------------------------------------------------
int DBSqlite::connect(const char *host, const char *user, const char *passwd, const char *dbName)
{
    if (sqlite3_open(dbName, &db) < 0)
    {
        return -DBERR_CONN;
    }

    isConnected = true;
    return DBERR_NOERR;
}
void DBSqlite::close()
{
    if (!isConnected) return;

    sqlite3_close(db);
    db = NULL;
    isConnected = false;
}
//---------------------------------------------------------------------------------------
int DBSqlite::execute(const char* sql)
{
    int ret = sqlite3_exec(db, sql, NULL, NULL, NULL);
    return ret == SQLITE_OK ? 0 : -1;
}
int DBSqlite::real_execute(const char* sql, vector<DBCol*> *pcols)
{
    int err_code = -DBERR_STMT;

    sqlite3_stmt *stmt;
    if (sqlite3_prepare( db, sql, -1, &stmt, 0 ) < 0) 
        return -DBERR_STMT;

    int parameter_count = sqlite3_bind_parameter_count(stmt);
    if (parameter_count != pcols->size())
    {
        err_code = -DBERR_SQL;
        goto out;
    }
	for (int i = 0; i < parameter_count; i++)
    {
        DBCol *pcol = pcols->at(i);
        if (sqlite3_bind_blob(stmt, i+1, pcol->data, pcol->len, NULL) != SQLITE_OK)
            goto out;
    }

    int ret = sqlite3_step(stmt);
    if (ret == SQLITE_DONE)
    {
        err_code = DBERR_NOERR;
        goto out;
    }
out:
    sqlite3_finalize(stmt);
    return err_code;
}

int DBSqlite::execute_with_result(const char* sql, std::vector<DBRow*> *records)
{
    int err_code = -DBERR_STMT;

    sqlite3_stmt *stmt;
    if (sqlite3_prepare( db, sql, -1, &stmt, 0 ) < 0) 
        return -DBERR_STMT;

    int parameter_count = sqlite3_bind_parameter_count(stmt);
    if (parameter_count != 0)
    {
        err_code = -DBERR_SQL;
        goto out;
    }
	
    int colCnt = sqlite3_column_count(stmt);
    while (sqlite3_step(stmt) == SQLITE_ROW)
    {
        DBRow* prow = new DBRow();
        for (int i = 0; i < colCnt; i++)
        {
            DBCol *pcol = new DBCol();
            int type = sqlite3_column_type(stmt, i);
            switch (type)
            {
            case SQLITE_BLOB:
                pcol->len = sqlite3_column_bytes(stmt, i);
                pcol->data = new char [pcol->len];
                pcol->alloced = 1;
                memcpy(pcol->data, sqlite3_column_blob(stmt, i), pcol->len);
                break;
            case SQLITE_TEXT:
                pcol->len = sqlite3_column_bytes(stmt, i);
                pcol->data = new char [pcol->len];
                pcol->alloced = 1;
                memcpy(pcol->data, sqlite3_column_text(stmt, i), pcol->len);
                break;
            case SQLITE_INTEGER:
                pcol->data = (void*)sqlite3_column_int(stmt, i);
                break;
            case SQLITE_FLOAT:
				{
                pcol->len = sizeof(double);
                pcol->data = new char [pcol->len];
                pcol->alloced = 1;
                double val = sqlite3_column_double(stmt, i);
                memcpy(pcol->data, &val, sizeof(double));
				}
                break;
            default:
                printk("DBSqlite: DataType[%d] not support!\n", type);
                printk("DBSqlite: SQL[%s]\n", sql);
                break;
            }
            prow->cols.push_back(pcol);
        }
        records->push_back(prow);
    }
    err_code = DBERR_NOERR;
out:
    sqlite3_finalize(stmt);
    return err_code;
}

const char* DBSqlite::db_error() const
{
    return sqlite3_errmsg(db);
}


//---------------------------------------------------------------------------------------
}
